﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Spanner
{
    public partial class UI
    {
        /// <summary>
        /// NewRegex(pattern) is equivalent to the JavaScript  new Regex(pattern).
        /// </summary>
        /// <param name="pattern"></param>
        /// <returns></returns>
        public static Expr<RegExp> NewRegExp(Expr<string> pattern, Expr<string> modifiers = null)
        {
            return
                  (object)modifiers == null
                ? JSExpr<RegExp>("new RegExp(#)", pattern)
                : JSExpr<RegExp>("new RegExp(#, #)", pattern, modifiers);
        }

        /// <summary>
        /// A regular expression value.
        /// </summary>
        public class RegExp { }

        // This is a placeholder class giving the signature of the result from Exec.
        // The pragmas suppress "field never used" warnings: these fields ARE
        // mirrored in the Spanner Javascript runtime.
        public class RegExpMatch
        {
#pragma warning disable 0169
            public string MatchedSubstr;
            public string[] ParenMatches;
            int MatchIndex;
            string MatchInput;
#pragma warning restore 0169
        }


        /// <summary>
        /// Exec(regex, x) is approximately equivalent to the JavaScript regex.exec(x).
        /// 
        /// Because Spanner's type system does not support JavaScript's notion of
        /// dynamically extending values with arbitrary properties.  To this end,
        /// this method returns a RegexMatch value rather than extending the regex
        /// value itself.
        /// 
        /// Note that JavaScript's exec method has a side effect on the regex value!
        /// This means you will see unexpected results if you expect Exec to be side-effect free!
        /// You need to create a fresh Regex instance for each string you match against.
        /// </summary>
        /// <param name="regex"></param>
        /// <param name="x"></param>
        /// <returns></returns>
        public static Expr<RegExpMatch> Exec(Expr<RegExp> regex, Expr<string> x)
        {
            return JSExpr<RegExpMatch>("spanner.regexExec(#, #)", regex, x);
        }

        /// <summary>
        /// MatchedSubstr(match) is equivalent to the JavaScript match.matchedSubstr
        /// where match was obtained from running Exec(regex, x) for some regex and x.
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public static Expr<string> MatchedSubstr(Expr<RegExpMatch> match)
        {
            return JSExpr<string>("#.MatchedSubstr", match);
        }

        /// <summary>
        /// ParenMatches(match) is equivalent to the JavaScript match.parenMatches
        /// where match was obtained from running Exec(regex, x) for some regex and x.
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public static Expr<string[]> ParenMatches(Expr<RegExpMatch> match)
        {
            return JSExpr<string[]>("#.ParenMatches", match);
        }

        /// <summary>
        /// ParenMatch(match, i) is equivalent to the JavaScript match.parenMatch[i]
        /// where match was obtained from running Exec(regex, x) for some regex and x.
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public static Expr<string> ParenMatch(Expr<RegExpMatch> match, Expr<int> i)
        {
            return JSExpr<string>("#.ParenMatches[#]", match, i);
        }

        /// <summary>
        /// MatchIndex(match) is equivalent to the JavaScript match.index
        /// where match was obtained from running Exec(regex, x) for some regex and x.
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public static Expr<int> MatchIndex(Expr<RegExpMatch> match)
        {
            return JSExpr<int>("#.MatchIndex", match);
        }

        /// <summary>
        /// MatchInput(match) is equivalent to the JavaScript match.input
        /// where match was obtained from running Exec(regex, x) for some regex and x.
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public static Expr<string> MatchInput(Expr<RegExpMatch> match)
        {
            return JSExpr<string>("#.MatchInput", match);
        }

        /// <summary>
        /// Test(regex, x) is equivalent to the JavaScript regex.test(x).
        /// </summary>
        /// <param name="regex"></param>
        /// <param name="x"></param>
        /// <returns></returns>
        public static Expr<bool> Test(Expr<RegExp> regex, Expr<string> x)
        {
            return JSExpr<bool>("#.test(#)", regex, x);
        }
    }
}
